//FACEBOOK ASYNC CLIENT

//FacebookAsyncUser methods

#include "facebookasync.h"

#include "xmlParser.h"
#include "md5.h"
#include <fstream>
#include <iostream>

#include "lang/lang.h"

int g_CurResultTxt = 0;

//UPDATE

void FacebookAsyncUser::Update(float dt)
{
	if (m_HasActiveRequest == false)
	{
		ProcessDelayedItems();
		return;
	}

	m_CurTransferTime += dt;

	if (m_CurTransferTime > FACEBOOK_TIMEOUT)
	{
		CancelCurrentRequest();
		return;
	}

	int RunningHandles;
	CURLMcode Res;
	do
	{
		Res = curl_multi_perform(m_pMultiCurl, &RunningHandles);
	}while(Res == CURLM_CALL_MULTI_PERFORM);

	//to make sure we don't have multiple requests!
	assert(RunningHandles < 2);
	
	//DEBUG CODE
	int Msgs = 0;
	CURLMsg* NewMsg = curl_multi_info_read(m_pMultiCurl, &Msgs);

	if (NewMsg != NULL)
	{
		Msgs = 10;
	}
	//END OF DEBUG CODE

	if (RunningHandles == 0) //some request is completed!
	{
		if (m_CurNotificationStage == NOTIFSTAGE_INPROGRESS)
			OnNotificationDone();

		if (m_CurPostFeedItemStage == POSTFEEDSTAGE_INPROGRESS)
			OnPostFeedItemDone();

		if (m_GenericCallInProgress == true)
			OnGenericCallDone();

		switch(m_CurLoginStage)
		{
		case LOGINSTAGE_GETTINGAUTHENTICATION:
			{
				LoginOnStageDone_Authentication();
			}
			break;

		case LOGINSTAGE_GETTINGLOGINPAGE:
			{
				LoginOnStageDone_GettingLoginPage();
			}
			break;

		case LOGINSTAGE_POSTINGLOGINPAGE:
			{
				LoginOnStageDone_PostingLoginPage();
			}
			break;

		case LOGINSTAGE_POSTINGDESKTOPAPPCONFIRM:
			{
				LoginOnStageDone_PostingDesktopAppConfirm();
			}
			break;

		case LOGINSTAGE_GETTINGFINALDESKTOPAPPPAGE:
			{
				LoginOnStageDone_GettingFinalDesktopAppPage();
			}
			break;

		case LOGINSTAGE_POSTINGCREATESESSION:
			{
				LoginOnStageDone_PostingCreateSession();
				return;
			}
			break;

		}

		switch(m_CurInfoStage)
		{
		case INFOSTAGE_GETTINGUSERINFO:
			{
				InfoOnStageDone_GettingUserInfo();
			}
			break;

		case INFOSTAGE_GETTINGUSERPHOTOSIZE:
			{
				InfoOnStageDone_GettingUserPhotoSize();
			}
			break;

		case INFOSTAGE_GETTINGFRIENDS:
			{
				InfoOnStageDone_GettingFriends();
			}
			break;

		case INFOSTAGE_GETTINGFRIENDSINFO:
			{
				InfoOnStageDone_GettingFriendsInfo();
			}
			break;

		case INFOSTAGE_GETTINGFRIENDSPHOTOSIZES:
			{
				InfoOnStageDone_GettingFriendsPhotoSizes();
				return;
			}
			break;
		}

		switch(m_CurPhotoStage)
		{
		case PHOTOSTAGE_GETTINGUSERPHOTO:
			{
				PhotoOnStageDone_GettingUserPhoto();
			}
			break;

		case PHOTOSTAGE_GETTINGFRIENDSPHOTOS:
			{
				PhotoOnStageDone_GettingFriendsPhotos();
				return;
			}
			break;

		}

	}

}



void FacebookAsyncUser::PushNewRequest()
{
	assert(m_HasActiveRequest == false);

	CURLMcode Res = curl_multi_add_handle(m_pMultiCurl, m_pCurl);

	assert(Res == CURLM_CALL_MULTI_PERFORM || Res == CURLM_OK);

	m_HasActiveRequest = true;

	m_CurTransferTime = 0.0f;
}


void FacebookAsyncUser::PullCompletedRequest()
{
	assert(m_HasActiveRequest == true);

	CURLMcode Res = curl_multi_remove_handle(m_pMultiCurl, m_pCurl);

	assert(Res == CURLM_CALL_MULTI_PERFORM || Res == CURLM_OK);

	m_HasActiveRequest = false;

	m_CurTransferTime = 0.0f;

	////saving new request into file
	//std::string NewFileName = "fb_req";
	//NewFileName.append(lang::Lang::FormatNumber(g_CurResultTxt++)); 
	//NewFileName.append(".txt");
	//std::ofstream CurFile(NewFileName.c_str());

	//CurFile << m_CurRequestResult;

	//CurFile.close();

}


void FacebookAsyncUser::CancelCurrentRequest()
{
	if (m_HasActiveRequest == false)
		return;

	//removing handle
	curl_multi_remove_handle(m_pMultiCurl, m_pCurl);

	m_HasActiveRequest = false;

	m_CurTransferTime = 0.0f;

	//for login
	if (m_CurLoginStage != LOGINSTAGE_NOTSTARTED && m_CurLoginStage != LOGINSTAGE_SUCCEED)
		m_CurLoginStage = LOGINSTAGE_FAILED;

	//for info
	if (m_CurInfoStage != INFOSTAGE_NOTSTARTED && m_CurInfoStage != INFOSTAGE_SUCCEED)
		m_CurInfoStage = INFOSTAGE_FAILED;

	//for photos
	if (m_CurPhotoStage != PHOTOSTAGE_NOTSTARTED && m_CurPhotoStage != PHOTOSTAGE_SUCCEED)
		m_CurPhotoStage = PHOTOSTAGE_FAILED;

	//for notification
	if (m_CurNotificationStage == NOTIFSTAGE_INPROGRESS)
		m_CurNotificationStage = NOTIFSTAGE_FAILED;

	//feed item posting
	if (m_CurPostFeedItemStage == POSTFEEDSTAGE_INPROGRESS)
		m_CurPostFeedItemStage = POSTFEEDSTAGE_FAILED; 

	FacebookAsync::Instance().MakeCallback();

}


//LOGIN RELATED ROUTINES

bool FacebookAsyncUser::StartLogin()
{
	assert(m_CurLoginStage == LOGINSTAGE_NOTSTARTED || m_CurLoginStage == LOGINSTAGE_FAILED); 

	m_CurLoginStage = LOGINSTAGE_NOTSTARTED;

	//TEST CODE
	curl_easy_cleanup(m_pCurl);
	m_pCurl = curl_easy_init();
	assert(m_pCurl != NULL);

	//starting first login stage: getting authentication
	LoginStartStage_Authentication();

	return true;
}//bool FacebookAsyncUser::StartLogin()



void FacebookAsyncUser::LoginStartStage_Authentication()
{
	assert(m_HasActiveRequest == false);

	std::list<std::string> Params;

	FacebookAsync::Instance().Helper_PrepareAPICall("facebook.auth.createToken", Params, this); 

	PushNewRequest();

	m_CurLoginStage = LOGINSTAGE_GETTINGAUTHENTICATION; 

	FacebookAsync::Instance().MakeCallback();

}


void FacebookAsyncUser::LoginOnStageDone_Authentication()
{
	assert(m_CurLoginStage == LOGINSTAGE_GETTINGAUTHENTICATION);

	PullCompletedRequest();

	//parsing result

	XMLNode Head = XMLNode::parseString(m_CurRequestResult.c_str(),NULL);
	XMLNode Node = Head.getChildNode(_T("auth_createToken_response"));

	if (Node.isEmpty())
	{
		FacebookAsync::Instance().SetErrorDescription("User Login Step 1 error. Xml parsing error!");

		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	//remembering the token
	m_LoginToken = Node.getText();

	//starting next login stage
	LoginStartStage_GettingLoginPage(); 

}



void FacebookAsyncUser::LoginStartStage_GettingLoginPage()
{

	//resetting the curl
	curl_easy_reset(m_pCurl);

	//creating url for get request
	m_BUFFER_LoginGetRequestURL = FacebookAsync::Instance().GetGlobalData_LoginURL();

	//appending params
	m_BUFFER_LoginGetRequestURL.append("?api_key=");
	m_BUFFER_LoginGetRequestURL.append(FacebookAsync::Instance().GetGlobalData_AppKey());
	m_BUFFER_LoginGetRequestURL.append("&auth_token=");
	m_BUFFER_LoginGetRequestURL.append(m_LoginToken);
	m_BUFFER_LoginGetRequestURL.append("&v=");
	m_BUFFER_LoginGetRequestURL.append(FACEBOOK_APIVER);

	//providing url to curl
	curl_easy_setopt(m_pCurl, CURLOPT_URL, m_BUFFER_LoginGetRequestURL.c_str());

	//telling curl it will be a GET request
	curl_easy_setopt(m_pCurl, CURLOPT_HTTPGET, true);

	//enabling cookies
	curl_easy_setopt(m_pCurl, CURLOPT_COOKIEFILE, "");

	//enabling redirections
	curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(m_pCurl, CURLOPT_MAXREDIRS, 100);

	//setting user agent - a subject to think about
	curl_easy_setopt(m_pCurl, CURLOPT_USERAGENT, FACEBOOK_USERAGENT);

	//setting the request result writing
	m_CurRequestResult = "";

	curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, FacebookAsync::Write_Callback);
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &m_CurRequestResult);	

	PushNewRequest();

	m_CurLoginStage = LOGINSTAGE_GETTINGLOGINPAGE; 

	FacebookAsync::Instance().MakeCallback();	
}



void FacebookAsyncUser::LoginOnStageDone_GettingLoginPage()
{
	assert(m_CurLoginStage == LOGINSTAGE_GETTINGLOGINPAGE);

	PullCompletedRequest();

	//std::ofstream TmpFile("getloginpage.txt");
	//TmpFile << m_CurRequestResult;
	//TmpFile.close();

	//checking if request was ok
	if (m_CurRequestResult.size() < 1)
	{
		FacebookAsync::Instance().SetErrorDescription("User Login Step 2 error. Request result is empty(initial GET request for login)!");

		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	//making some checks to get a chance of finding out that something was changed on facebook site
	std::string::size_type FindLoc;

	//Check1.1. secure http login url
	FindLoc = m_CurRequestResult.find(FACEBOOK_SECURELOGINURL);
	if (FindLoc == std::string::npos)
	{
		FacebookAsync::Instance().ReportFacebookSiteChanged();
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 2 ERROR. SECURE HTTP LOGIN URL WAS CHANGED!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	//THIS CHECK IS REMOVED
	//Check1.2. login info text
	//FindLoc = m_CurRequestResult.find("Login to Facebook to enjoy the full functionality");
	//if (FindLoc == std::string::npos)
	//{
	//	FacebookAsync::Instance().ReportFacebookSiteChanged();
	//	FacebookAsync::Instance().SetErrorDescription("User Login STEP 2 ERROR. LOGIN PAGE WAS CHANGED!");
	//	m_CurLoginStage = LOGINSTAGE_FAILED;
	//	FacebookAsync::Instance().SetLastFailedRequest(m_CurRequestResult);
	//	FacebookAsync::Instance().MakeCallback();
	//	return;
	//}
	
	//Check1.3. Main input fields
	//app token
	FindLoc = m_CurRequestResult.find("auth_token");
	if (FindLoc == std::string::npos)
	{
		FacebookAsync::Instance().ReportFacebookSiteChanged();
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 2 ERROR. LOGIN PAGE WAS CHANGED: auth_token is missing!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}
	//api key
	FindLoc = m_CurRequestResult.find("api_key");
	if (FindLoc == std::string::npos)
	{
		FacebookAsync::Instance().ReportFacebookSiteChanged();
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 2 ERROR. LOGIN PAGE WAS CHANGED: api_key is missing!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}
	//email
	FindLoc = m_CurRequestResult.find("email");
	if (FindLoc == std::string::npos)
	{
		FacebookAsync::Instance().ReportFacebookSiteChanged();
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 2 ERROR. LOGIN PAGE WAS CHANGED: email is missing!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}
	//pass
	FindLoc = m_CurRequestResult.find("pass");
	if (FindLoc == std::string::npos)
	{
		FacebookAsync::Instance().ReportFacebookSiteChanged();
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 2 ERROR. LOGIN PAGE WAS CHANGED: pass is missing!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}
	//charset_test
	FindLoc = m_CurRequestResult.find("charset_test");
	if (FindLoc == std::string::npos)
	{
		FacebookAsync::Instance().ReportFacebookSiteChanged();
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 2 ERROR. LOGIN PAGE WAS CHANGED: charset_test is missing!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	//after the checks we assume that it is safe to continue

	//starting next login stage
	LoginStartStage_PostingLoginPage(); 

}



void FacebookAsyncUser::LoginStartStage_PostingLoginPage()
{

	//now we prepare curl to make http POST request to secure login url
	
	//resetting the curl
	curl_easy_reset(m_pCurl);

	//setting request url
	curl_easy_setopt(m_pCurl, CURLOPT_URL, FACEBOOK_SECURELOGINURL);

	//setting SSL params - the ones that work
	curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYPEER, 0);
	curl_easy_setopt(m_pCurl, CURLOPT_SSL_VERIFYHOST, 0);

	//aggregating POST params
	m_BUFFER_LoginPOSTParams = "";

	//version
	m_BUFFER_LoginPOSTParams.append("version=");
	m_BUFFER_LoginPOSTParams.append(FACEBOOK_APIVER);
	//token
	m_BUFFER_LoginPOSTParams.append("&auth_token=");
	m_BUFFER_LoginPOSTParams.append(m_LoginToken);
	//api key
	m_BUFFER_LoginPOSTParams.append("&api_key=");
	m_BUFFER_LoginPOSTParams.append(FacebookAsync::Instance().GetGlobalData_AppKey());
	//email
	m_BUFFER_LoginPOSTParams.append("&email=");
	m_BUFFER_LoginPOSTParams.append(m_UserEmail);
	//password
	m_BUFFER_LoginPOSTParams.append("&pass=");
	m_BUFFER_LoginPOSTParams.append(m_UserPassword);
	//chareset test
	m_BUFFER_LoginPOSTParams.append("&charset_test=");
	m_BUFFER_LoginPOSTParams.append("%E2%82%AC%C2%B4%E2%82%AC%C2%B4%E6%B0%B4%D0%94%D0%84");

	//telling curl that it will be a POST request and setting POST fields
	curl_easy_setopt(m_pCurl, CURLOPT_HTTPPOST, true );
	curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, m_BUFFER_LoginPOSTParams.c_str());

	//enabling redirections
	curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(m_pCurl, CURLOPT_MAXREDIRS, 100);

	//setting user agent - a subject to think about
	curl_easy_setopt(m_pCurl, CURLOPT_USERAGENT, FACEBOOK_USERAGENT);

	//setting the request result writing
	m_CurRequestResult = "";

	curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, FacebookAsync::Write_Callback);
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &m_CurRequestResult);	

	//making the request
	PushNewRequest();

	m_CurLoginStage = LOGINSTAGE_POSTINGLOGINPAGE; 

	FacebookAsync::Instance().MakeCallback();
}



void FacebookAsyncUser::LoginOnStageDone_PostingLoginPage()
{
	assert(m_CurLoginStage == LOGINSTAGE_POSTINGLOGINPAGE);

	PullCompletedRequest();

	//std::ofstream TmpFile("postloginpage.txt");
	//TmpFile << m_CurRequestResult;
	//TmpFile.close();

	if (m_CurRequestResult.size() < 1)
	{
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 2 ERROR. Request result is empty(secure POST request for login)!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}	

	//checking if login is complete
	std::string::size_type FindLoc;



	//checking if login/password was incorrect
	FindLoc = m_CurRequestResult.find(m_UserEmail);
	if (FindLoc != std::string::npos)
	{
		FacebookAsync::Instance().ReportInvalidLoginPassword(); 
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 2 ERROR. User provided incorrect email/password.");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	FindLoc = m_CurRequestResult.find("BrainCurve Desktop</title>");
	if (FindLoc == std::string::npos)
	{
		FacebookAsync::Instance().SetErrorDescription("");

		//jumping to create session stage
		LoginStartStage_PostingCreateSession(); 
		return;
	}

	//starting next stage
	LoginStartStage_PostingDesktopAppConfirm(); 

}



void FacebookAsyncUser::LoginStartStage_PostingDesktopAppConfirm()
{

	//checking if we've got a right page
	std::string::size_type FindLoc;

	//Check 2.1
	FindLoc = m_CurRequestResult.find("confirmation_login_content");
	if (FindLoc == std::string::npos)
	{
		FacebookAsync::Instance().ReportFacebookSiteChanged();
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 3 ERROR. Confirmation page was changed! no confirmation_login_content!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	//Check 2.2
	FindLoc = m_CurRequestResult.find(FACEBOOK_DESKTOPAPP_APPROVEMENTURL);
	std::string::size_type FindLoc2 = m_CurRequestResult.find(FACEBOOK_DESKTOPAPP_NEWAPPROVEMENTURL);
	if (FindLoc == std::string::npos && FindLoc2 == std::string::npos)
	{
		FacebookAsync::Instance().ReportFacebookSiteChanged();
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 3 ERROR. STEP 3 ERROR. Desktop app approvement URL was changed!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	if (FindLoc != std::string::npos)
		m_CurApproveURL = FACEBOOK_DESKTOPAPP_APPROVEMENTURL;
	else
		m_CurApproveURL == FACEBOOK_DESKTOPAPP_NEWAPPROVEMENTURL;

	//m_CurApproveURL = FACEBOOK_DESKTOPAPP_APPROVEMENTURL;

	//now we assume that the page is right and we continue

	//extracting post form id value
	FindLoc = m_CurRequestResult.find("post_form_id");
	FindLoc = m_CurRequestResult.find("value", FindLoc);
	char TempChars[2] = {34, 0};
	FindLoc = m_CurRequestResult.find(TempChars, FindLoc);
	if (FindLoc == std::string::npos)
	{
		FacebookAsync::Instance().ReportFacebookSiteChanged();
		FacebookAsync::Instance().SetErrorDescription("User Login STEP 3 ERROR. Error in extracting post form id value!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	std::string PostFormID = m_CurRequestResult.substr(FindLoc+1, 32);

	//now we prepare curl to make http POST request to desktop app confirmation url

	//resetting the curl
	curl_easy_reset(m_pCurl);

	//setting request url
	curl_easy_setopt(m_pCurl, CURLOPT_URL, FACEBOOK_DESKTOPAPP_APPROVEMENTURL);

	//aggregating POST params
	m_BUFFER_LoginPOSTParams = "";

	//grant_perm
	m_BUFFER_LoginPOSTParams.append("grant_perm=1");
	//next
	m_BUFFER_LoginPOSTParams.append("&next=");
	//api key
	m_BUFFER_LoginPOSTParams.append("&api_key=" + FacebookAsync::Instance().GetGlobalData_AppKey());
	//auth_token
	m_BUFFER_LoginPOSTParams.append("&auth_token=" + m_LoginToken);
	//post form id
	m_BUFFER_LoginPOSTParams.append("&post_form_id=" + PostFormID);

	//telling curl that it will be a POST request and setting POST fields
	curl_easy_setopt(m_pCurl, CURLOPT_HTTPPOST, true );
	curl_easy_setopt(m_pCurl, CURLOPT_POSTFIELDS, m_BUFFER_LoginPOSTParams.c_str());

	//enabling redirections
	curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(m_pCurl, CURLOPT_MAXREDIRS, 100);

	//setting user agent - a subject to think about
	curl_easy_setopt(m_pCurl, CURLOPT_USERAGENT, FACEBOOK_USERAGENT);

	//setting the request result writing
	m_CurRequestResult = "";

	curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, FacebookAsync::Write_Callback);
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &m_CurRequestResult);	
	//setting callback func for this new user

	PushNewRequest();

	m_CurLoginStage = LOGINSTAGE_POSTINGDESKTOPAPPCONFIRM; 

	FacebookAsync::Instance().MakeCallback();
}



void FacebookAsyncUser::LoginOnStageDone_PostingDesktopAppConfirm()
{
	assert(m_CurLoginStage == LOGINSTAGE_POSTINGDESKTOPAPPCONFIRM);

	PullCompletedRequest();

	if (m_CurRequestResult.size() < 1)
	{
		FacebookAsync::Instance().SetErrorDescription("User Login Step 3 error. Request result is empty(POST request for desktop app confirmation page)!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	//LoginStartStage_PostingCreateSession(); 
	LoginStartStage_GettingFinalDesktopAppPage(); 

}



void FacebookAsyncUser::LoginStartStage_GettingFinalDesktopAppPage()
{
	//resetting the curl
	curl_easy_reset(m_pCurl);

	//creating url for get request
	m_BUFFER_LoginGetRequestURL = FACEBOOK_DESKTOPAPP_FINALURL; 

	//appending params
	m_BUFFER_LoginGetRequestURL.append("?api_key=");
	m_BUFFER_LoginGetRequestURL.append(FacebookAsync::Instance().GetGlobalData_AppKey());

	//providing url to curl
	curl_easy_setopt(m_pCurl, CURLOPT_URL, m_BUFFER_LoginGetRequestURL.c_str());

	//telling curl it will be a GET request
	curl_easy_setopt(m_pCurl, CURLOPT_HTTPGET, true);

	//enabling redirections
	curl_easy_setopt(m_pCurl, CURLOPT_FOLLOWLOCATION, 1);
	curl_easy_setopt(m_pCurl, CURLOPT_MAXREDIRS, 100);

	//setting user agent - a subject to think about
	curl_easy_setopt(m_pCurl, CURLOPT_USERAGENT, FACEBOOK_USERAGENT);

	//setting the request result writing
	m_CurRequestResult = "";

	curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, FacebookAsync::Write_Callback);
    curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, &m_CurRequestResult);	

	PushNewRequest();

	m_CurLoginStage = LOGINSTAGE_GETTINGFINALDESKTOPAPPPAGE; 

	FacebookAsync::Instance().MakeCallback();

}



void FacebookAsyncUser::LoginOnStageDone_GettingFinalDesktopAppPage()
{
	assert(m_CurLoginStage == LOGINSTAGE_GETTINGFINALDESKTOPAPPPAGE);

	PullCompletedRequest();

	//std::ofstream TmpFile("finaldtapppage.txt");
	//TmpFile << m_CurRequestResult;
	//TmpFile.close();



	std::string::size_type FindLoc;

	FindLoc = m_CurRequestResult.find("confirmation_login_content");
	if (FindLoc == std::string::npos)
	{
		FacebookAsync::Instance().SetErrorDescription("");
	}
	else
	{
		FacebookAsync::Instance().SetErrorDescription("LOGIN ERROR. SITE CHANGED - FINAL DESKTOP APP URL");
		FacebookAsync::Instance().ReportFacebookSiteChanged();
	}

	//TODO TEST CODE
	Sleep(1000);

	//jumping to create session stage
	LoginStartStage_PostingCreateSession(); 

}



void FacebookAsyncUser::LoginStartStage_PostingCreateSession()
{

	Sleep(5000);

	std::list<std::string> Params;

	Params.push_back("auth_token=" + m_LoginToken);

	//Params.push_back("generate_session_secret=true");

	FacebookAsync::Instance().Helper_PrepareAPICall("facebook.auth.getSession", Params, this); 

	PushNewRequest();

	m_CurLoginStage = LOGINSTAGE_POSTINGCREATESESSION; 

	FacebookAsync::Instance().MakeCallback();

}


void FacebookAsyncUser::LoginOnStageDone_PostingCreateSession()
{
	assert(m_CurLoginStage == LOGINSTAGE_POSTINGCREATESESSION);

	PullCompletedRequest();	

	if (m_CurRequestResult.size() < 1)
	{
		FacebookAsync::Instance().SetErrorDescription("User Login error. Cannot create session!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	XMLNode Head = XMLNode::parseString(m_CurRequestResult.c_str( ), NULL);
	XMLNode Result = Head.getChildNode(_T("auth_getSession_response"));

	//session key
	XMLNode Node = Result.getChildNode(_T("session_key"));

	if (Node.isEmpty())
	{
		FacebookAsync::Instance().SetErrorDescription("User Login error. Session key wasn't passed!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	m_LoginSession = Node.getText();

	//session secret
	Node = Result.getChildNode(_T("secret"));

	if (Node.isEmpty())
	{
		FacebookAsync::Instance().SetErrorDescription("User Login error. Session secret wasn't passed!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	m_SessionSecret = Node.getText();

	//user id
	Node = Result.getChildNode(_T("uid"));

	if (Node.isEmpty())
	{
		FacebookAsync::Instance().SetErrorDescription("User Login error. User id wasn't passed!");
		m_CurLoginStage = LOGINSTAGE_FAILED;
		FacebookAsync::Instance().MakeCallback();
		return;
	}

	m_UserID = Node.getText();

	//success
	FacebookAsync::Instance().SetErrorDescription(""); 
	m_CurLoginStage = LOGINSTAGE_SUCCEED; 
	FacebookAsync::Instance().MakeCallback();

	if (m_AutoFetch == true)
	{
		FacebookAsync::Instance().CurUser_StartFetchingInfo();
	}

}



void FacebookAsyncUser::ProcessDelayedItems()
{
	if (m_CurPhotoStage != PHOTOSTAGE_SUCCEED && m_CurPhotoStage != PHOTOSTAGE_FAILED)
		return;

	//generic calls first
	int DelayedGenCallsSize = (int)m_DelayedGenericCalls.size();

	if (DelayedGenCallsSize > 0)
	{
		//making generic call
		MakeGenericCall(m_DelayedGenericCalls.at(DelayedGenCallsSize-1));

		m_DelayedGenericCalls.pop_back();
		return;
	}

	//notifications first

	int DelayedNotifSize = (int)m_DelayedNotifications.size(); 

	if (DelayedNotifSize > 0)
	{
		//sending last notification
		SendNotification(m_DelayedNotifications.at(DelayedNotifSize-1).m_UserIDs,
						 m_DelayedNotifications.at(DelayedNotifSize-1).m_NotificationFBML);

		m_DelayedNotifications.pop_back();
		return;
	}

	//then - news feed items
	
	int DelayedFeedItemsSize = (int)m_DelayedNewsFeedItems.size();

	if (DelayedFeedItemsSize > 0)
	{
		//sending last feed item
		PostFeedItem(m_DelayedNewsFeedItems.at(DelayedFeedItemsSize-1).m_ItemType,
					 m_DelayedNewsFeedItems.at(DelayedFeedItemsSize-1).m_FeedItemInfo);

		m_DelayedNewsFeedItems.pop_back();
		return;
	}
}





































